import { UserService } from './../../service/userService';
import { User, UserType } from './../../domain/models/user';
import { DataRegister } from './../../domain/models/dataRegister';
import * as Koa from 'koa';
import { Transaction } from 'tiny-entity2';
import { Guid, route, RouteOptionsVerify, ServiceManager, Tools, UsingLock } from "../../common";
import { ServiceException } from '../../common/excpetion';
import { ApiDataContext } from '../../domain/apiDataContext';
import { Organization } from '../../domain/models/organization';
import { OrganizationTree } from '../../domain/models/organizationTree';
import { OrganizationService } from '../../service/organizationService';
import { OrganizationTreeService } from '../../service/organizationTreeService';
import { DataRegisterService } from '../../service/dataRegisterService';
import { Account } from '../../domain/models/account';
import md5 = require('md5');
import { AccountService } from '../../service/accountService';
import Enumerable = require('linq');
const orgSvr = ServiceManager.Current.GetService<OrganizationService>('OrganizationService');
const orgTreeSvr = ServiceManager.Current.GetService<OrganizationTreeService>('OrganizationTreeService');
const dSvr = ServiceManager.Current.GetService<DataRegisterService>('DataRegisterService');
const userSvr = ServiceManager.Current.GetService<UserService>('UserService');
const accSvr = ServiceManager.Current.GetService<AccountService>('AccountService');

class OrganizationController {
    @route(new RouteOptionsVerify('GET', '/api/organization'))
    async queryOrganizations(ctx: Koa.Context, next) {
        let params = ctx.query;
        let organization = await orgSvr.QueryOrganization(params);
        ctx.response.body = organization;
        await next();
    }

    @route(new RouteOptionsVerify('GET', '/api/organization/:id'))
    async getOrganizationInfoById(ctx: Koa.Context, next) {
        let id = ctx.params.id;

        let data = await orgSvr.GetOrganizationById(id);
        let orgtrees: OrganizationTree[] = await orgTreeSvr.QueryOrganizationTree({ objectName: "Organization", objectId: id });

        if (data) {
            data.orgTree = <OrganizationTree>{};
            if (orgtrees && orgtrees.length > 0) {
                data.orgTree = orgtrees[0];
            }
        }

        ctx.response.body = data;
        await next();
    }
    @route(new RouteOptionsVerify('POST', '/api/organization'))
    async createOrganization(ctx: Koa.Context, next) {
        let rootOrgId = ctx.headers['orgid'];
        let org: Organization = ctx.request.body;

        checkOrgData(org);
        var today = Date.now();
        org.modifyTime = today;
        org.isDelete = false;
        org.id = Guid.GetGuid();
        ctx.response.body = await UsingLock(org.name, async () => {
            return await Transaction(new ApiDataContext(), async datactx => {
                let result = await orgSvr.CreateOrganization(org, datactx);
                let orgTree = new OrganizationTree();
                orgTree.id = Guid.GetGuid();
                orgTree.isDelete = false;
                if (rootOrgId && rootOrgId != "") {
                    orgTree.organizationId = rootOrgId;
                    orgTree.isRoot = false;
                }
                else {
                    orgTree.organizationId = result.id;
                    orgTree.isRoot = true;
                }

                orgTree.objectId = result.id;
                orgTree.objectName = result.ClassName();

                orgTree.nodeName = result.name;
                orgTree.parentId = org.orgTree.parentId;

                result.orgTree = await orgTreeSvr.CreateorganizationTree(orgTree, datactx);

                //创建管理员账号
                let adminUser = new User();
                adminUser.userType = UserType.Admin;
                adminUser.name = '管理员';
                adminUser.createTime = Date.now();
                adminUser.phone = org.phone;
                adminUser.organizationId = org.id;

                adminUser = await userSvr.CreateUser(adminUser, datactx);

                let userTreeNode = new OrganizationTree();
                userTreeNode.objectId = adminUser.id;
                userTreeNode.objectName = adminUser.ClassName();
                userTreeNode.nodeName = adminUser.name;
                userTreeNode.parentId = orgTree.id;
                userTreeNode.id = Guid.GetGuid();
                userTreeNode.isDelete = false;

                await orgTreeSvr.CreateorganizationTree(userTreeNode, datactx);

                adminUser.orgTree = userTreeNode;

                let ac = new Account();
                ac.id = Guid.GetGuid();
                ac.username = adminUser.phone;
                ac.password = md5('123456');

                await accSvr.CreateAccount(ac, datactx);

                return result;
            });
        })

        await next();
    }
    @route(new RouteOptionsVerify('PUT', '/api/organization'))
    async updateOrganization(ctx: Koa.Context, next) {
        let org: Organization = ctx.request.body;
        if (!org.id) {
            throw new ServiceException('id 不能为空！', 'not_be_null');
        }
        checkOrgData(org);
        var today = Date.now();
        org.modifyTime = today;
        ctx.response.body = await UsingLock(org.id, async () => {
            return await Transaction(new ApiDataContext(), async datactx => {
                let orgData = await orgSvr.GetOrganizationById(org.id);
                orgData = Tools.ConvertToObject(org, orgData);
                let result = await orgSvr.UpdateOrganization(orgData, datactx);

                let orgtrees = await orgTreeSvr.QueryOrganizationTree({ objectId: result.id });
                let orgtree: OrganizationTree = new OrganizationTree();
                if (orgtrees && orgtrees.length > 0) {
                    orgtree = orgtrees[0];
                }

                orgtree.nodeName = org.name;
                orgtree.parentId = orgData.orgTree.parentId;

                result.orgTree = await orgTreeSvr.UpdateorganizationTree(orgtree, datactx);
                return result;
            });
        })

        await next();
    }
    @route(new RouteOptionsVerify('DELETE', '/api/organization/:id'))
    async deleteOrganization(ctx: Koa.Context, next) {
        let id = ctx.params.id;

        if (!id) {
            throw new ServiceException('id 不能为空！', 'not_be_null');
        }
        let organization = await orgSvr.GetOrganizationById(id);
        organization.isDelete = true;

        ctx.response.body = await UsingLock(organization.id, async () => {
            return await Transaction(new ApiDataContext(), async datactx => {
                let result = await orgSvr.UpdateOrganization(organization, datactx);
                organization.orgTree.isDelete = true;
                await orgTreeSvr.UpdateorganizationTree(organization.orgTree, datactx);
                return result;
            })
        })

        await next();
    }

    @route(new RouteOptionsVerify('POST', '/api/orgCodeRule'))
    async createOrgCodeRule(ctx: Koa.Context, next) {
        let orgId = ctx.headers['orgid'];
        let data: any[] = ctx.request.body;

        await UsingLock(orgId + "_create_orgCodeRule", async () => {
            return await Transaction(new ApiDataContext(), async ctx => {
                let has = await dSvr.GetDataRegisterByDataTypeAndObjectId("orgCodeSetting", orgId);
                if (has) {
                    has.data = data;
                    await dSvr.UpdateDataRegister(has, ctx);
                }
                else {
                    let item = new DataRegister();
                    item.id = Guid.GetGuid();
                    item.data = data;
                    item.dataType = 'orgCodeSetting';
                    item.objectId = orgId;
                    item.objectType = 'organization';
                    await dSvr.CreateDataRegister(item, ctx);
                }

                await orgSvr.DeleteOrgCodeRuleByOrgId(orgId);

                let orgCodeSeedDatas = [];

                data.forEach(item => {
                    orgCodeSeedDatas = orgCodeSeedDatas.concat(item.orgCodeItems.filter(x => x.type == "settled"));
                })

                for (let item of orgCodeSeedDatas) {
                    let has = await orgSvr.GetOrgCodeSeedById(item.id);
                    if (has) {
                        item.orgId = has.orgId;
                        item.createTime = has.createTime;
                        await orgSvr.UpdateOrgCodeSeed(item, ctx);
                    }
                    else {
                        item.orgId = orgId;
                        item.value = item.value - 1;
                        await orgSvr.CreateOrgCodeSeed(item, ctx);
                    }
                }
            })
        });

        ctx.response.body = {};
        await next();
    }

    @route(new RouteOptionsVerify('GET', '/api/organization/:id/orgCodeRule'))
    async queryOrgCodeRuleAndSeed(ctx: Koa.Context, next) {
        let orgId = ctx.params.id;
        ctx.response.body = await dSvr.GetDataRegisterByDataTypeAndObjectId("orgCodeSetting", orgId);
        await next();
    }


    @route(new RouteOptionsVerify('PUT', '/api/organization/:id/orgCodeSeed/:seedId'))
    async updateOrgCodeSeed(ctx: Koa.Context, next) {
        let orgId = ctx.headers['orgid'];
        let seedId = ctx.params.seedId;

        let r = await UsingLock(seedId, async () => {
            let orgSeed = await orgSvr.GetSettledCode([], { id: seedId });
            await orgSvr.UpdateOrgCodeSeed(orgSeed);
            return orgSeed;
        });

        ctx.response.body = r;
        await next();
    }

    @route(new RouteOptionsVerify('GET', '/api/orgCodeRule/gcode'))
    async getNewCode(ctx: Koa.Context, next) {
        let { orgCodeRuleName } = ctx.query;
        let orgId = ctx.headers['orgid'];

        ctx.response.body = await orgSvr.GenerateNewCode(orgCodeRuleName, orgId);
        await next();
    }

    @route(new RouteOptionsVerify('POST', '/api/organization/copyConfig'))
    async copyOrgConfig(ctx: Koa.Context, next) {
        let data: {
            sourceOrgId: string;
            targetOrgIds: string[]
        } = ctx.request.body;

        const loclKey = md5(Enumerable.from(data.targetOrgIds).orderBy(x => x).toArray().join(','));
        await UsingLock(loclKey, async () => {
            return await Transaction(new ApiDataContext(), async ctx => {
                for (let orgId of data.targetOrgIds) {
                    await orgSvr.CopyOrgConfig({
                        sourceOrgId: data.sourceOrgId,
                        targetOrgId: orgId
                    });
                }
            });
        })

        ctx.response.body = {};

        await next();
    }

}

const checkOrgData = (org: Organization) => {
    if (!org.name) {
        throw new ServiceException('未填写组织名称！');
    }
    if (!org.phone) {
        throw new ServiceException('未填写组织电话！');
    }
    // if (!org.code) {
    //     throw new ServiceException('未填写组织代码！');
    // }

}